#ifndef MESHMAKER_H
#define MESHMAKER_H

#include <vector>
#include "common.h"
#include "TreeMesh.h"
#include "constants.h"

struct ControlRing{
    std::vector<double3>* points;
    std::vector<double3>* tangents;
    Bud * associated_bud;
    double3          center, normal;
    float           radius;
    ControlRing(){
        center.x = 0.0;
        center.y = 0.0;
        center.z = 0.0;
        normal.x = 0.0;
        normal.y = 0.0;
        normal.z = 0.0;
        points = new std::vector<double3>();
        tangents = new std::vector<double3>();
    }

};

struct ControlDisc{
    Plane plane;
    double radius;
    Bud*   bud;
    vector<double3>* points;

    ControlDisc(){
        plane.normal = double3(0.0,1.0,0.0);
        plane.point  = double3(0.0,0.0,0.0);
        radius       = 0.0;
        bud          = NULL;
        points       = new vector<double3>();
    }

    ControlDisc(Bud* b, double3 p, double3 n, double r){
        plane.normal = n;
        plane.point  = p;
        radius       = r;
        bud          = b;
        points       = new vector<double3>();

        const double ang2 = (double)b->phi + .5 * M_PI;
        double ang;
        double proj;
        const double theta = b->theta;

        double3 pt;

        const double r2 = radius * radius;
        for(double i = 0.0; i < VERTS_PER_RING; i += 1.0){
            ang = (2.0 * M_PI * i / VERTS_PER_RING);

            pt.y  = -radius * cos(ang) * cos(ang2);
            proj = sqrt(r2 - pt.y * pt.y);

            pt.x = proj * cos(ang + theta);
            pt.z = proj * -sin(ang + theta);

            pt += plane.point;
            points->push_back(pt);
        }
    }

    ControlDisc(Bud* b, double3 p, double3 n, vector<double3>* vec){
        plane.normal = n;
        plane.point  = p;
        radius       = b->diameter * .5;
        bud          = b;
        points       = new vector<double3>();

        for(int i = 0; i < vec->size(); i++)
            points->push_back(vec->at(i));
    }

    ControlDisc(const ControlDisc& disc){
        plane.normal = disc.plane.normal;
        plane.point  = disc.plane.point;
        radius       = disc.radius;
        bud          = disc.bud;
        points       = disc.points;
    }
};

void convexHull(std::vector<ControlDisc>* list, TreeMesh* mesh);
void addMultipleRingsToMesh(std::vector<ControlRing>* list, TreeMesh* m);

void buildMeshRecursivelyFromRoot(TreeMesh* mesh, Bud* bud);
void buildMeshRecursively(TreeMesh* mesh, Bud* bud, ControlRing &start);

void makeControlRing(Bud *bud, double rad, float3 &center, float3 &end, double phi, double theta,  double offThet, ControlRing &ring);

void resolveOverlaps(ControlRing &old, ControlRing &end, ControlRing& auxRing, ControlRing &termRing, bool &useCollar);

void correctForCenter(ControlRing& auxRing);

void makeLeafs(Bud* bud,TreeMesh* mesh);

void buildMeshRecursivelyTwo(TreeMesh* mesh, ControlDisc &s);

void build(TreeMesh* mesh, Bud* root);

void correctForCenter(ControlDisc& auxRing);

void makeLeafs2(Bud *bud, TreeMesh *mesh);

#endif // MESHMAKER_H
